#include "syscall.h"

int main()
{

	int input;
	int i = 0;
	int lockIndex;
	int lockIndex2;
	int condIndex;
	int condIndex2;
	int maxLocks = 20;
	int maxConditions = 40;

	Write("Part 2 Test Cases Menu\n\n", 26, 1);
	Write("0 - Test Yield\n", 16, 1);
	Write("1 - Test Creating Locks\n",25, 1);
	Write("2 - Test Aquiring Locks\n",25, 1);
	Write("3 - Test Releasing Locks\n", 26, 1);
	Write("4 - Test Destroying Locks\n", 27, 1);
	Write("5 - Test Create Condition\n", 27, 1);
	Write("6 - Test Signal Condition\n", 27, 1);
	Write("7 - Test Wait Condition\n", 25, 1);
	Write("8 - Test Broadcast Condition\n", 30, 1);
	Write("9 - Test Destroy Condition\n", 28, 1); 
	input = GetInputInt("Input", 5);


	switch(input)
	{
		case 0:
			Write("\nTesting Yield\n", 15, 1);
			Yield(1);
			break;
		
		/******************Create Lock Tests**********************/
		case 1:

			Write("Tests For Creating Locks                \n", 42, 1);
			
			/*Correct use of locks, should complete*/
			Write("Test: Creating lock correctly           \n", 42, 1);
			CreateLock();
			
			Write("\nTest: Creating multiple locks correctly \n", 44, 1);
			for(i = 0; i <= 3; i++)
			{
				/*CreateLock() returns position in lock array of the current lock being created*/
				lockIndex = CreateLock();
			}
			
			Write("Test: Creating, Aquiring, Released locks correctly\n", 52, 1);
			lockIndex = CreateLock();/*CreateLock() returns position in lock array of the current lock being created*/
			Acquire(lockIndex,1);/*Acquires lock and lock array position lockIndex. if returns 0, passes*/
			Release(lockIndex,1);/*Releases lock and lock array position lockIndex. if returns 0, passes*/
			
			/*Incorrect use of locks, */
			Write("Test: Creating more than max number of locks           \n", 60, 1);
			for(i = 0; i < maxLocks; i++) 
			{
				/*CreateLock() returns position in lock array of the current lock being created*/
				lockIndex = CreateLock();
			}			

			break;
		

		/****************Acquire Lock Tests**********************/
		case 2:
			Write("Tests for Acquiring Locks\n", 27 ,1);
			
			/*Correct Usage of Acquire()*/
			Write("Test: Acquiring a created lock..........\n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			
			Write("Test: Create, Acquire, Release, Acquire\n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex,1);
			Acquire(lockIndex,1);

			Write("Test: Trying to Acquire already acquired lock\n", 47, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Acquire(lockIndex,1);
			
			/*Incorrect Usage of Acquire()*/
			Write("Test: Trying to Acquire a nonexistent lock\n", 44, 1);
			Acquire(100,1);
		
			Write("Test: Trying to Acquire a lock out of array size\n", 52, 1);
			Acquire(1000,1);
		
			Write("Test: Trying to Acquire a lock at negative index\n", 52, 1);
			Acquire(-10,1);
			break;

		/******************Release Lock Tests************************/
		case 3:
			Write("Tests for Releasing Locks\n", 27, 1);
			
			/*Correct Usage of Release()*/
			Write("Test: Releasing an acquired lock        \n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex,1);

			Write("Test: Releasing a recently created lock \n", 42, 1);
			lockIndex = CreateLock();
			Release(lockIndex,1);

			/*Incorrect Usage of Release()*/
			
			/*this test requires -d to see the debug message from synch.h*/
			Write("Test: Releasing a recently released lock\n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex,1);
			Release(lockIndex,1);

			
			Write("Test: Releasing a nonexistent lock index\n", 42, 1);
			Release(500,1);
			
			Write("Test: Releasing a negative lock index   \n", 42, 1);
			Release(-10,1);
			break;
		
		/********************Destroying Lock Tests**********************/
		case 4:
			Write("Tests for Destroying Locks\n", 26, 1);
			
			/*Correct Usage of Destory Lock*/
			Write("Test: Destory a created lock            \n", 42, 1);
			lockIndex = CreateLock();
			DestroyLock(lockIndex);

			Write("[Test]Destory after acquiring a lock    \n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			DestroyLock(lockIndex);

			Write("[Test]Destory after acquiring, then releasing a lock    \n", 57, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex,1);
			DestroyLock(lockIndex);

			/*Incorrect Usage of Destroy Lock*/
			Write("[Test]Destory a nonexistent lock index  \n", 42, 1);
			DestroyLock(500);
			
			Write("[Test]Destroy a negative lock index     \n", 42, 1);
			DestroyLock(-12);
			
			
			Write("[Test]Destroy an already destroyed lock index\n", 47, 1);
			lockIndex = CreateLock();
			DestroyLock(lockIndex);
			DestroyLock(lockIndex);
			break;
	
		/***********************Creating Condition Variables**********************/
		case 5:
			
    			Write("Tests for Creating Conditions\n", 31, 1); 
    
    			/*Correct Usage of Create Conditions*/
   			Write("[Test] Creating conditions properly\n",37, 1); 
   			CreateCondition();
    
    			Write("[Test] Creating multiple different Condition Variables\n", 56, 1); 
  			for (i = 0; i < 3; i++)
    			{
        			CreateCondition(); 
    			}
    
   

			/*Incorrect use of conditions, */
			Write("Test: Creating more than max number of conditions  \n", 60, 1);
			for(i = 0; i < maxConditions+1; i++)
			{
				/*CreateCondition() returns position in condition array of the current lock being created*/
				condIndex = CreateCondition();
			}
		
			break;
		/**********************Signal for Condition Variables***************************/
		case 6:
			
    
    			Write("Tests for Signaling         \n\n", 30, 1);
    
    			/*Correct usage of Signals*/
    			Write("[Test] Signaling on created Condition \n", 40, 1);
    			lockIndex = CreateLock();
        		Acquire(lockIndex,1);
        		condIndex = CreateCondition();
    			Signal(lockIndex, condIndex ); 

        		Write("[Test] Signaling same condition twice on the same lock\n",56,1);
    			lockIndex = CreateLock();
        		Acquire(lockIndex,1);
        		condIndex = CreateCondition();
    			Signal( lockIndex,condIndex); 
        		Signal( lockIndex,condIndex);

        		Write("[Test] Signaling same condition twice on different locks\n",58,1);
    			lockIndex = CreateLock();
        		lockIndex2 = CreateLock();
        		Acquire(lockIndex,1);
        		Acquire(lockIndex2,1);
        		condIndex = CreateCondition();
    			Signal(lockIndex,condIndex); 
        		Signal(lockIndex2,condIndex);
    
    			/*Write("[Test] Signaling after a Wait on same lock\n",46, 1);
       			lockIndex = CreateLock();
        		Aquire(lockIndex);
       			condIndex = CreateCondition();
    			Wait( lockIndex,condIndex);
   			Signal(lockIndex,condIndex);*/

        		Write("[Test] Signaling after Broadcast\n", 34,1);
        		lockIndex = CreateLock();
        		Acquire(lockIndex,1);
        		condIndex = CreateCondition();
    			Broadcast(lockIndex, condIndex);
        		Signal(lockIndex, condIndex);
    
    			

    			/*Incorrect Usage*/
			Write("[Test] Incorrect Usage              \n", 38, 1);

    			Write("[Test] Signaling non-intialized lock\n", 38, 1);
        		condIndex = CreateCondition();
    			Signal(500, condIndex); 
        		

			Write("[Test] Signaling non-initialized condition variable\n", 53, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);;
			Signal(lockIndex, 601); 
			

			Write("[Test] Signaling non-initialized lock and condition variable\n", 62, 1);
			Signal(550, 540);
			

			

			Write("[Test] Signaling un-acquired lock\n", 35, 1);
			lockIndex = CreateLock();
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex); 
			
			Write("[Test] Signaling an already released lock\n", 43, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex); 
			
			Write("[Test] Signalling destroyed lock\n", 34, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			DestroyLock(lockIndex);
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex);
			
			
			/*These tests should be run in debug (-d)*/
			Write("[Test] Signaling out of bounds lock\n", 37, 1);
			condIndex = CreateCondition();
			Signal(1000,condIndex); 
			
			Write("[Test] Signaling out of bounds CV\n", 35, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Signal(lockIndex, 1001); 
			
			
			Write("[Test] Signaling out of bounds lock and CV\n", 44, 1);
			Signal(1002, 1003); 
			
		
			Write("[Test] Signaling negative lock index\n", 38, 1);
			condIndex = CreateCondition();
			Signal(-10, condIndex);
			
			Write("[Test] Signaling negative condition index\n", 43, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Signal(lockIndex, -11);
			
			Write("[Test] Signaling negative lock and condition index\n", 52, 1);
			Signal(-12, -13);
			break;

		/**********************Wait for Condition Variables***************************/
		case 7:	
    		
			Write("Tests for Waiting           \n", 30, 1);

			/**Correct Usage of Wait for Condition Variables**/
			Write("[Test] Waiting on recently created Condition\n", 46, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Signal(lockIndex,condIndex);
			Wait(lockIndex, condIndex);

			Write("[Test] Waiting on a created Condition twice in a row on same lock\n", 67, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);  
			Wait(lockIndex, condIndex);

			Write("[Test] Waiting on a created Condition twice in a row on different locks\n", 73, 1);
			lockIndex = CreateLock();
			lockIndex2 = CreateLock();
			Acquire(lockIndex,1);
			Acquire(lockIndex2,1);
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);  
			Wait(lockIndex2, condIndex);
			 
			Write("[Test] Waiting after a signal on same lock\n", 44, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex);
			Wait(lockIndex, condIndex);
		
			Write("[Test] Waiting after a broadcast on same lock\n", 47, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);
			Wait(lockIndex, condIndex);
		
	
			/**Incorrect usage of Wait**/
			Write("[Test] Waiting on not yet created lock index\n", 46, 1);
			condIndex = CreateCondition();
			Wait(100,condIndex);  

			Write("[Test] Waiting on not yet created condIndex\n", 45, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Wait(lockIndex, 101);  
			
			Write("[Test] Waiting on yet to be created lock and condition index\n", 62, 1);
			Wait(150, 151);
			 
			Write("[Test] Waiting on a yet to be acquired lock\n", 45, 1);
			lockIndex = CreateLock();
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);  
			 
			Write("[Test] Waiting on a released lock index\n", 41, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);  
			 
			Write("[Test] Waiting on a destroyed lock index\n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			DestroyLock(lockIndex);
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);
			 
			/*These tests must be run in debug (-d)*/
			Write("[Test] Waiting on an out-of-bounds lock index\n", 47, 1);
			condIndex = CreateCondition();
			Wait( 1000,condIndex);  
			 
			Write("[Test] Waiting on a condition index that is out of bounds\n", 59, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Wait( lockIndex,1001);  
			 
			Write("[Test] Waiting on out of bounds lock and condition index\n", 58, 1);
			Wait(1002, 1003);  
			 
			Write("[Test] Waiting on a negative lockIndex\n", 40, 1);
			condIndex = CreateCondition();
			Wait( -10,condIndex);
			 
			Write("[Test] Waiting on a negative condition index\n", 46, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Wait(lockIndex,-11);
				 
			Write("[Test] Waiting on a negative lock and condition index\n", 55, 1);
			Wait(-12, -13);
			break;


		/**********************Broadcast for Condition Variables***************************/
		case 8:	
			Write("Tests for Broadcast         \n", 30, 1);
			
			/*Correct use of Broadcast*/
			Write("[Test] Broadcasting on created Condition\n", 42, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  
			 

			Write("[Test] Broadcasting on same Condition twice on same lock\n", 58, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  
			Broadcast(lockIndex, condIndex);
			 

			Write("[Test] Broadcasting on same Condition twice on different locks\n", 64, 1);
			lockIndex = CreateLock();
			lockIndex2 = CreateLock();
			Acquire(lockIndex,1);
			Acquire(lockIndex2,1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  
			Broadcast(lockIndex2, condIndex);
			 
		
			/*Write("[Test] Broadcasting after waiting on same lock\n", 64, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);;
			condIndex = CreateCondition();
			Wait(lockIndex, condIndex);
			Broadcast(lockIndex, condIndex);
			 */

			Write("[Test] Broadcasting after signaling on same lock\n", 50, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex);
			Broadcast(lockIndex, condIndex);
		 
			Write("[Test] Broadcasting after signaling on different lock\n", 55, 1);
			lockIndex = CreateLock();
			lockIndex2= CreateLock();
			Acquire(lockIndex,1);
			Acquire(lockIndex2,1);
			condIndex = CreateCondition();
			Signal(lockIndex, condIndex);
			Broadcast(lockIndex2, condIndex);
		
			/*Incorrect Usage of Broadcast*/
			Write("[Test] Broadcasting on uninitialized lock and CV\n", 50, 1);
			Broadcast(100, 101);
			 
			Write("[Test] Broadcasting on uninitialized lock       \n", 50, 1);
			condIndex = CreateCondition();				
			Broadcast(100, condIndex);

			Write("[Test] Broadcasting on uninitialized CV         \n", 50, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Broadcast(lockIndex, 101);

			Write("[Test] Broadcasting on unacquired lock\n", 40, 1);
			lockIndex = CreateLock();
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  
			 

			Write("[Test] Broadcasting on a released lock\n", 40, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  
			 

			Write("[Test] Broadcasting on a destroyed lock\n", 41, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex, 1);
			DestroyLock(lockIndex);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);
			 

			/*These tests need to be run in debug (-d) */
			 
			Write("[Test] Broadcasting on out of bounds lock and condition index\n", 63, 1);
			Broadcast(1000, 1001);  
			 
			Write("[Test] Broadcasting on out of bounds lock  index\n", 50, 1);
			condIndex = CreateCondition();			
			Broadcast(1000, condIndex);  

			Write("[Test] Broadcasting on out of bounds  condition index\n", 55, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Broadcast(lockIndex, 1001);  

			Write("[Test] Broadcasting on negative lock  index\n", 45, 1);
			condIndex = CreateCondition();
			Broadcast(-10, condIndex);

			Write("[Test] Broadcasting on negative  condition index\n", 50, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Broadcast(lockIndex, -11);

			Write("[Test] Broadcasting on negative lock and condition index\n", 58, 1);
			Broadcast(-10, -11);

			Write("[Test] Broadcasting on unacquired lock                  \n", 58, 1);
			lockIndex = CreateLock();
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex);  

			Write("[Test] Broadcasting on released   lock                  \n", 58, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			Release(lockIndex,1);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex); 

			Write("[Test] Broadcasting on destroyed   lock                  \n", 58, 1);
			lockIndex = CreateLock();
			Acquire(lockIndex,1);
			DestroyLock(lockIndex);
			condIndex = CreateCondition();
			Broadcast(lockIndex, condIndex); 

			break;
			 	
		/**********************Destroying Condition Variables***************************/
		case 9:	
			Write("Tests for Destroying Condition Variables\n", 42, 1);			 
    
  			/*Correct usage of Destroyig Conditions*/
    			Write("[Test] Destroy Condition index after it was created  \n", 57, 1); 
    			condIndex = CreateCondition();
    			DestroyCondition(condIndex);
    
     
    
    			Write("[Test] Destroying condition index after signal       \n", 57, 1); 
    			lockIndex = CreateLock();
        		condIndex = CreateCondition();
    			Signal(lockIndex, condIndex);
    			DestroyCondition(condIndex);
    
     
    
    			/*Write("[Test] Destroy condition index after waiting\n", 64, 1); 
    			lockIndex = CreateLock();
        		condIndex = CreateCondition();
    			Wait(lockIndex,condIndex);
    			DestroyCondition(condIndex);
         		*/
    

    
    			/*Incorrect Usage of Destroy*/
    			Write("[Test] Destroying yet to be created condition index \n", 57, 1); 
    			DestroyCondition(100);
     
    
    			Write("[Test] Destroying already destroyed condition index \n", 57, 1); 
    			condIndex = CreateCondition(); 
    			DestroyCondition(condIndex);
    			DestroyCondition(condIndex);
     
    
    			Write("[Test] Destroying a condition multiple times        \n", 57, 1); 
    			condIndex = CreateCondition();
    			for(i=0; i<3; i++)
    			{
     			   DestroyCondition(condIndex);
    			}
     
     
    			Write("[Test] Destroying out of bounds condition index     \n", 57, 1);
    			DestroyCondition(1000);
     

        		Write("[Test] Destroying negative condition index          \n", 57, 1);
    			DestroyCondition(-10);
			break;
     



}
























